Skip to content

feat(react-motion): add replayKey prop to replay motion without remounting#36108

Merged
robertpenner merged 13 commits into
microsoft:masterfrom
robertpenner:feat/motion-component-replay-key
May 14, 2026
Merged

feat(react-motion): add replayKey prop to replay motion without remounting#36108
robertpenner merged 13 commits into
microsoft:masterfrom
robertpenner:feat/motion-component-replay-key

Conversation

@robertpenner
Copy link
Copy Markdown
Collaborator

@robertpenner robertpenner commented May 6, 2026

  • Add an optional replayKey prop to MotionComponentProps.
  • When the value changes, the animation effect re-runs — cancelling any in-progress animation and replaying from the start on the same DOM element, without remounting the component or its children.
  • Includes tests verifying replay behaviour, DOM continuity, callbacks firing on replay (onMotionStart/onMotionFinish), and skip-motion fast-forward on replay.
  • Adds a Storybook story with a side-by-side before/after demo.
image

Previous Behavior

To retrigger a motion animation on an already-mounted component, the only declarative option was to change the React key prop, which forces a full unmount and remount of the subtree. This destroys the DOM nodes, resets child component state, and loses focus — even when all you want is to replay the animation.

New Behavior

MotionComponent accepts an optional replayKey prop (string | number). When the value changes, the animation replays from the beginning on the existing DOM element — cancelling any in-progress animation — without unmounting or remounting the component or its children. DOM continuity, focus, and child state are all preserved.

const [replayKey, setReplayKey] = React.useState(0);

<Fade.In replayKey={replayKey}>
  <div>Content</div>
</Fade.In>
<button onClick={() => setReplayKey(k => k + 1)}>Replay</button>

Future Work

@robertpenner robertpenner self-assigned this May 6, 2026
@robertpenner robertpenner force-pushed the feat/motion-component-replay-key branch from dd35075 to 0967549 Compare May 6, 2026 05:57
@robertpenner robertpenner force-pushed the feat/motion-component-replay-key branch from 0967549 to 864d814 Compare May 7, 2026 14:35
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
react-accordion
Accordion (including children components)
92.107 kB
29.097 kB
92.29 kB
29.158 kB
183 B
61 B
react-charts
AreaChart
402.548 kB
125.863 kB
402.733 kB
125.933 kB
185 B
70 B
react-charts
DeclarativeChart
753.368 kB
220.084 kB
753.553 kB
220.142 kB
185 B
58 B
react-charts
DonutChart
312.961 kB
96.495 kB
313.146 kB
96.557 kB
185 B
62 B
react-charts
FunnelChart
304.508 kB
93.326 kB
304.693 kB
93.394 kB
185 B
68 B
react-charts
GanttChart
385.649 kB
120.152 kB
385.832 kB
120.201 kB
183 B
49 B
react-charts
GaugeChart
312.394 kB
95.948 kB
312.579 kB
96.01 kB
185 B
62 B
react-charts
GroupedVerticalBarChart
393.525 kB
122.894 kB
393.71 kB
122.944 kB
185 B
50 B
react-charts
HeatMapChart
387.728 kB
121.263 kB
387.913 kB
121.327 kB
185 B
64 B
react-charts
HorizontalBarChart
292.691 kB
89.04 kB
292.876 kB
89.106 kB
185 B
66 B
react-charts
Legends
232.228 kB
69.849 kB
232.411 kB
69.909 kB
183 B
60 B
react-charts
LineChart
413.882 kB
128.765 kB
414.067 kB
128.815 kB
185 B
50 B
react-charts
PolarChart
341.357 kB
106.417 kB
341.542 kB
106.47 kB
185 B
53 B
react-charts
SankeyChart
209.97 kB
67.042 kB
210.155 kB
67.111 kB
185 B
69 B
react-charts
ScatterChart
393.264 kB
122.86 kB
393.449 kB
122.912 kB
185 B
52 B
react-charts
VerticalBarChart
430.006 kB
127.714 kB
430.191 kB
127.783 kB
185 B
69 B
react-charts
VerticalStackedBarChart
399.594 kB
124.306 kB
399.779 kB
124.355 kB
185 B
49 B
react-components
react-components: Accordion, Button, FluentProvider, Image, Menu, Popover
226.994 kB
68.166 kB
227.177 kB
68.237 kB
183 B
71 B
react-components
react-components: entire library
1.292 MB
324.684 kB
1.292 MB
324.744 kB
185 B
60 B
react-dialog
Dialog (including children components)
91.172 kB
28.31 kB
91.357 kB
28.379 kB
185 B
69 B
react-menu
Menu (including children components)
160.425 kB
50.891 kB
160.608 kB
50.95 kB
183 B
59 B
react-menu
Menu (including selectable components)
163.603 kB
51.535 kB
163.786 kB
51.594 kB
183 B
59 B
react-motion
@fluentui/react-motion - createMotionComponent()
4.156 kB
1.818 kB
4.339 kB
1.881 kB
183 B
63 B
react-motion
@fluentui/react-motion - createPresenceComponent()
5.908 kB
2.442 kB
6.091 kB
2.501 kB
183 B
59 B
react-popover
Popover
123.802 kB
39.735 kB
123.985 kB
39.799 kB
183 B
64 B
react-progress
ProgressBar
20.23 kB
7.866 kB
20.413 kB
7.931 kB
183 B
65 B
react-teaching-popover
TeachingPopover
102.196 kB
32.335 kB
102.379 kB
32.394 kB
183 B
59 B
react-toast
Toast (including Toaster)
92.099 kB
28.662 kB
92.284 kB
28.722 kB
185 B
60 B
react-tree
FlatTree
136.789 kB
40.787 kB
136.972 kB
40.849 kB
183 B
62 B
react-tree
PersonaFlatTree
138.617 kB
41.303 kB
138.8 kB
41.362 kB
183 B
59 B
react-tree
PersonaTree
134.677 kB
40.086 kB
134.86 kB
40.146 kB
183 B
60 B
react-tree
Tree
132.855 kB
39.62 kB
133.038 kB
39.679 kB
183 B
59 B
Unchanged fixtures
Package & Exports Size (minified/GZIP)
react-avatar
Avatar
48.492 kB
15.379 kB
react-avatar
AvatarGroup
17.468 kB
6.999 kB
react-avatar
AvatarGroupItem
61.513 kB
19.251 kB
react-breadcrumb
@fluentui/react-breadcrumb - package
103.889 kB
29.167 kB
react-charts
HorizontalBarChartWithAxis
63 B
83 B
react-charts
Sparkline
80.503 kB
26.644 kB
react-components
react-components: Button, FluentProvider & webLightTheme
67.61 kB
19.536 kB
react-components
react-components: FluentProvider & webLightTheme
40.806 kB
13.616 kB
react-datepicker-compat
DatePicker Compat
214.121 kB
62.046 kB
react-headless-components-preview
react-headless-components-preview: entire library
127.463 kB
37.413 kB
react-message-bar
MessageBar (all components)
23.418 kB
8.651 kB
react-motion
@fluentui/react-motion - PresenceGroup
1.727 kB
823 B
react-overflow
hooks only
11.966 kB
4.565 kB
react-persona
Persona
55.447 kB
17.311 kB
react-portal-compat
PortalCompatProvider
5.567 kB
2.237 kB
react-table
DataGrid
148.07 kB
44.013 kB
react-table
Table (Primitives only)
38.209 kB
12.782 kB
react-table
Table as DataGrid
119.815 kB
33.806 kB
react-table
Table (Selection only)
66.603 kB
19.023 kB
react-table
Table (Sort only)
65.246 kB
18.638 kB
react-tag-picker
@fluentui/react-tag-picker - package
174.546 kB
54.381 kB
react-tags
InteractionTag
13.742 kB
5.473 kB
react-tags
Tag
29.666 kB
9.433 kB
react-tags
TagGroup
71.009 kB
21.901 kB
react-timepicker-compat
TimePicker
105.613 kB
35.351 kB
🤖 This report was generated against c2c6c2d4a7b2d4801d0121bf48bca511a9c82eae

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

Pull request demo site: URL

@robertpenner robertpenner marked this pull request as ready for review May 7, 2026 15:32
@robertpenner robertpenner requested review from a team as code owners May 7, 2026 15:32
@robertpenner robertpenner requested a review from layershifter May 7, 2026 15:32
@robertpenner robertpenner force-pushed the feat/motion-component-replay-key branch from 68ec731 to bc88d21 Compare May 8, 2026 15:23
@robertpenner robertpenner moved this to Ready for review in 🏄🏻‍♂️ Fluent Motion May 8, 2026
@robertpenner robertpenner force-pushed the feat/motion-component-replay-key branch 2 times, most recently from fce9549 to 9a7dac0 Compare May 12, 2026 13:37
@robertpenner robertpenner force-pushed the feat/motion-component-replay-key branch from 9a7dac0 to bf6125e Compare May 14, 2026 16:10
@robertpenner robertpenner force-pushed the feat/motion-component-replay-key branch from bf6125e to 1fb6429 Compare May 14, 2026 16:32
@robertpenner robertpenner enabled auto-merge (squash) May 14, 2026 16:32
@robertpenner robertpenner disabled auto-merge May 14, 2026 16:38
@robertpenner robertpenner enabled auto-merge (squash) May 14, 2026 17:01
The cancelMock count assertion assumed React 18+ StrictMode double-invoke
of effects, which doesn't exist in React 17. play() being untouched is
the cross-version replay signal that actually expresses the test's intent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@robertpenner robertpenner merged commit 49adb67 into microsoft:master May 14, 2026
11 checks passed
@github-project-automation github-project-automation Bot moved this from Ready for review to Done in 🏄🏻‍♂️ Fluent Motion May 14, 2026
@robertpenner robertpenner deleted the feat/motion-component-replay-key branch May 14, 2026 19:23
mainframev pushed a commit to mainframev/fluentui that referenced this pull request May 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Development

Successfully merging this pull request may close these issues.

2 participants